/*******************************************************************************
 * Copyright (c) 2012 Daniele Parisi.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     Daniele Parisi
 *     neb.inf@gmail.com
 *     http://www.danieleparisi.com/
 ******************************************************************************/
package org.jxreport.html;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.jxreport.core.HTMLUtils;
import org.jxreport.core.Table;
import org.jxreport.core.XMLUtils;
import org.jxreport.core.XMLValues;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class HTMLReportGenerator{

	protected String title;
	protected String cssScript;
	protected HashMap<String, String> cssProperties =  new HashMap<String, String>();
	protected List<HTMLView> views = new LinkedList<HTMLView>();

	protected DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
	
	public HTMLReportGenerator() {}

	public HTMLReportGenerator(Document dom, Table table, boolean validateSchema) throws Exception {
		this.initFromDOM(dom, table, validateSchema);
	}

	public HTMLReportGenerator(Document dom, Table table) throws Exception {
		this.initFromDOM(dom, table, true);
	}
	
	public HTMLReportGenerator(InputStream xmlPath, Table table) throws Exception {
		Document dom = dbf.newDocumentBuilder().parse(xmlPath);
		this.initFromDOM(dom, table, true);
	}
	
	public HTMLReportGenerator(InputStream xmlPath, Table table, boolean validateSchema) throws Exception {
		Document dom = dbf.newDocumentBuilder().parse(xmlPath);
		this.initFromDOM(dom, table, validateSchema);
	}
	
	public HTMLReportGenerator(String textContent, Table table) throws Exception{
		Document dom = dbf.newDocumentBuilder().parse(new InputSource(new StringReader(textContent)));
		this.initFromDOM(dom, table, true);
	}

	public HTMLReportGenerator(String textContent, Table table, boolean validateSchema) throws Exception{
		Document dom = dbf.newDocumentBuilder().parse(new InputSource(new StringReader(textContent)));
		this.initFromDOM(dom, table, validateSchema);
	}
	
	protected String getReportJSCode() {
		String code = "";
		for (HTMLView reportView : this.views)
			code += reportView.getJQueryCode();
		
		return code;
	}
	
	protected String getBodyCSSCode()
	{
		String css = "body { ";
		for (String cssProperty : this.getCssProperties().keySet())
			css += cssProperty + ": " + this.getCssProperties().get(cssProperty) + "; ";
		
		css += "} ";
		return css;
	}
	
	protected String getCSSCode() {
		String code = "";
		for (HTMLView reportView : this.views)
			code += HTMLUtils.getCSSCode(reportView);
		
		return code;
	}
	
	protected String getReportHTMLBodyCode() {
		String code = "";
		for (HTMLView reportView : this.views)
			code += HTMLUtils.getDIVCode(reportView);
		
		return code;
	}
	
	public String getHTMLCode(){
		String code = 
		"<!DOCTYPE html>" + 
		"<html lang=\"it\">" + 
		   "<HEAD>" +
		   		"<meta name=\"Author\" content=\"Daniele Parisi\">" +
		   		"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" +
		      	"<TITLE>" + this.getTitle() + "</TITLE>" + 
//		      	"<!-- JQPLOT INCLUDES -->" + 
//		      	//"<script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-1.7.1.min.js\"></script>" +
//		      	"" + 
//		      	//"<script type=\"text/javascript\" src=\"DataTables-1.9.3/media/js/jquery.dataTables.min.js\"></script>" +
//		      	"<link rel=\"stylesheet\" type=\"text/css\" href=\"DataTables-1.9.3/media/css/demo_table.css\"></script>" +
//		      	"" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/jquery.jqplot.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.barRenderer.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.categoryAxisRenderer.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.dateAxisRenderer.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.canvasTextRenderer.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.canvasAxisTickRenderer.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.canvasAxisLabelRenderer.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.pointLabels.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.pieRenderer.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.donutRenderer.min.js\"></script>" + 
//				"<script type=\"text/javascript\" src=\"jqPlot/plugins/jqplot.highlighter.min.js\"></script>" +
//				"" + 
//				"<link rel=\"stylesheet\" type=\"text/css\" href=\"jqPlot/jquery.jqplot.css\" />" + 
//				"" + 
				"<!-- JS LIBRARY SCRIPTS -->" + 
				"<script>" +
					HTMLUtils.getJSScriptCode() + //this.getJSCode() + 
				"</script>" +				
				"" +
				"<!-- CSS LIBRARY SCRIPTS -->" + 
				"<style type=\"text/css\">" +
					HTMLUtils.getCSScriptCode() + 
				"</style>" +
				"" + 
				"<style type=\"text/css\">" +
					this.getBodyCSSCode() + 
					this.getCssScript() + 
					this.getCSSCode() +
				"</style>" +
				"<!-- END JQPLOT INCLUDES -->" +
				"<script>" +
					"$(document).ready(function(){" + 
						this.getReportJSCode() + 
					"});" +
				"</script>" +
			"</HEAD>" +
			"<BODY>" +
				this.getReportHTMLBodyCode() +
			"</BODY>" + 
		"</HTML>";
		
		return code;      
	}

	protected void initFromDOM(Document dom, Table table, boolean validateSchema) throws Exception{
		
//		String language = XMLConstants.W3C_XML_SCHEMA_NS_URI;
//		SchemaFactory factory = SchemaFactory.newInstance(language);
	    //SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

//		URL url = ClassLoader.getSystemResource("schema.xsd");
//		URL url = getClass().getResource("schema.xsd");
//		URI uri = url.toURI(); // new URI(url.toString());

//		try{
//		System.out.println("URL: " + url);
//		System.out.println("URI: " + uri);
//		}catch(Exception e ){}
//		Schema schema = factory.newSchema(new File(uri));

//		File schemaFile = new File(Thread.currentThread().getContextClassLoader().getResource("schema.xsd").getFile());
//		Schema schema = factory.newSchema(schemaFile);

		//Schema schema = factory.newSchema(this.getClass().getClassLoader().getResourceAsStream("schema.xsd"));
	   
//		
//	    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//	    factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
//	    factory.setAttribute(JAXP_SCHEMA_SOURCE, schemaTemp);

		// Validating Schema
		if(validateSchema)
		{
			File schemaTemp = new File("temp.xsd");
			//InputStream inputStream= new FileInputStream("InputStreamToFile.java");
			InputStream inputStream = HTMLReportGenerator.class.getResourceAsStream("schema.xsd");
			OutputStream out=new FileOutputStream(schemaTemp);
			byte buf[]=new byte[1024];
			int len;
			while((len=inputStream.read(buf))>0)
				out.write(buf,0,len);
			out.close();
			inputStream.close();
			
		    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
			Schema schema = factory.newSchema(schemaTemp);
			Validator validator = schema.newValidator();
			validator.validate(new DOMSource(dom));
		}
		
		Element docEle = dom.getDocumentElement();

		/************ GET REPORT GENERAL PROPERTIES *********************/
//		NodeList nl = docEle.getChildNodes();
//		if(nl != null && nl.getLength() > 0) {
//			for(int i = 0 ; i < nl.getLength();i++) {
//				
//				Node node = nl.item(i);
//				if(node.getNodeName().equals(XMLValues.TITLE))
//					this.setTitle(node.getTextContent());
//				else if(node.getNodeName().equals(XMLValues.CSS))
//				{
//					NodeList nl2 = node.getChildNodes();
//					for(int j = 0 ; j < nl2.getLength();j++) {
//						Node cssNode = nl2.item(j);
//						if(!cssNode.getNodeName().equals("#text"))
//							this.cssProperties.put(cssNode.getNodeName(), cssNode.getTextContent());
//					}
//				}
//			}
//		}

		this.setTitle(XMLUtils.getTextValue(docEle, XMLValues.HTML_TITLE));
		if(this.title == null) this.title = "My Report Title";
		
		this.setCssScript(XMLUtils.getTextValue(docEle, XMLValues.CSS_SCRIPT));
		if(this.cssScript == null) this.cssScript = "";

		NodeList nl = docEle.getElementsByTagName(XMLValues.CSS_BODY);
		if(nl.getLength() > 0) 
		{
			Element cssElement = (Element)nl.item(0);
			NodeList nl2 = cssElement.getElementsByTagName(XMLValues.CSS_RULE);
			for(int i = 0 ; i < nl2.getLength();i++) {
				Element el = (Element)nl2.item(i);
				this.cssProperties.put(XMLUtils.getTextValue(el, XMLValues.RULE_NAME), 
						XMLUtils.getTextValue(el, XMLValues.RULE_VALUE));
			}
		}
		/*********************************************************************/
		
		
		nl = docEle.getElementsByTagName("*");
//		Element reportElement = (Element)rnl.item(0);
//		nl = reportElement.getElementsByTagName("*");
		//NodeList nl = docEle.getChildNodes();
		if(nl != null && nl.getLength() > 0) {
			for(int i = 0 ; i < nl.getLength();i++) {
				//get the employee element
				Element el = (Element)nl.item(i);

				if(el.getParentNode().getNodeName().equals(XMLValues.REPORT))
				{
					HTMLView htmlrv = HTMLUtils.getDOMElementToHTMLObjectClass(el, null);
					if(htmlrv != null) 
						this.views.add(htmlrv);
				}
				
//				if(el.getNodeName().equals(XMLValues.CHART_LINE_CONTENT))
//					htmlrv = new HTMLLineChartView(el, table);
//				else if(el.getNodeName().equals(XMLValues.CHART_BAR_CONTENT))
//					htmlrv = new HTMLBarChartView(el, table);
//				else if(el.getNodeName().equals(XMLValues.CHART_PIE_CONTENT))
//					htmlrv = new HTMLPieChartView(el, table);
//				else if(el.getNodeName().equals(XMLValues.TWO_COLS))
//					htmlrv = new HTMLTwoColsView(el, table);
//				else if(el.getNodeName().equals(XMLValues.TEXT_CONTENT))
//					htmlrv = new HTMLTextContentView(el, table);
//				else if(el.getNodeName().equals(XMLValues.TABLE_CONTENT))
//					htmlrv = new HTMLTableView(el, table);

//				if(htmlrv != null) 
//				{
//					System.out.println(el.getParentNode().getNodeName());
//
//					this.views.add(htmlrv);
//				}
			}
		}
	}

	public List<HTMLView> getViews() {
		return views;
	}

	public void setViews(List<HTMLView> views) {
		this.views = views;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getCssScript() {
		return cssScript;
	}

	public void setCssScript(String cssScript) {
		this.cssScript = cssScript;
	}

	public HashMap<String, String> getCssProperties() {
		return cssProperties;
	}

	public void setCssProperties(HashMap<String, String> cssProperties) {
		this.cssProperties = cssProperties;
	}
}
